/*
 * @Author: hanyuanjiao yudongxiang93@163.com
 * @Date: 2025-07-21 06:52:28
 * @LastEditors: Please set LastEditors
 * @LastEditTime: 2025-08-17 07:57:27
 * @FilePath: /simu8051/tools.c
 * @Description: 工具类函数,tools.h的实现
 */
#include "tools.h"
#include <string.h>
#include <malloc.h>
#include "mem.h"
#include "simu8051.h"

void itoa(char *str, int num0, int base)
{
    static const char *digits = "0123456789ABCDEF";
    char              *curr   = str;
    if (base != 2 && base != 10 && base != 16)
    {
        *curr = '\0';
        return;
    }
    if (num0 < 0 && base == 10)
    {
        *curr++ = '-';
    }
    unsigned int num = (base != 10 || num0 >= 0) ? num0 : -num0;
    char         str_buf[20];
    memset(str_buf, '\0', sizeof(str_buf));
    int i = 0;
    do
    {
        char ch      = digits[num % base];
        str_buf[i++] = ch;
        /*
        if(tmp>=10){
            str_buf[i++] = tmp-10+'a';
        }else{
            str_buf[i++] = tmp+'0';
        }
        */
        num /= base;
    } while (num);
    if (base == 16)
    {
        str_buf[i++] = 'x';
        str_buf[i++] = '0';
    }
    while (i--)
    {
        *curr++ = str_buf[i];
    }
    *curr = '\0';
}

char *u8toBinary(uint8_t value)
{
    char *str = (char *)malloc(sizeof(char) * 33);
    memset(str, 0, 33);
    uint32_t v = value & 0xff;
    itoa(str, v, 2);
    return str;
}
/**
 * @description: 从buf中读取字符串,转换为数字
 * @param {uint8_t} *buf
 * @param {int} width
 * @return {*} width宽度的数字
 */
static int read_hex(uint8_t *buf, int width)
{
    int num = 0;
    for (int i = 0; i < width; i++)
    {
        char c = buf[i];
        if ((c >= '0') && (c <= '9'))
        {
            num = (num << 4) | (c - '0');
        }
        else if ((c >= 'a') && (c <= 'f'))
        {
            num = (num << 4) | ((c - 'a') + 10);
        }
        else if ((c >= 'A') && (c <= 'F'))
        {
            num = (num << 4) | ((c - 'A') + 10);
        }
    }
    return num;
}

uint8_t *simu8051_load_hexfile(const char *filename)
{
    /**
     * 每行由冒号开头
     * A 数据长度 1byte
     * B 数据的起始地址 2byte
     * C 数据类型 1byte
     *     00数据记录,01文件结束记录,02扩展段地址记录,03开始段地址记录,04扩展线性地址记录,05开始线性地址记录 D 具体数据
     * Nbyte,与A一致 E 校验和 1byte
     */
    uint8_t line_buf[HEX_LINE_SIZE];
    FILE   *file = fopen(filename, "r");
    if (file == NULL)
    {
        printf("open file failed:%s\n", filename);
        return NULL;
    }
    uint8_t *code = (uint8_t *)malloc(64 * 1024);
    memset(code, 0, 64 * 1024);
    if (code == NULL)
    {
        printf("malloc failed.\n");
        return NULL;
    }
    while (fgets((char *)line_buf, sizeof(line_buf), file))
    {
        uint8_t *c = line_buf;
        if (*c++ != ':')
        {
            fclose(file);
            free(code);
            return NULL;
        }
        uint8_t count = read_hex(c, 2);
        c += 2;
        uint16_t addr = read_hex(c, 4);
        c += 4;
        uint8_t type = read_hex(c, 2);
        c += 2;
        switch (type)
        {
        case HEX_TYPE_DATA:
            for (uint8_t idx = 0; idx < count; idx++, c += 2)
            {
                code[addr++] = read_hex(c, 2);
            }
            break;
        case HEX_TYPE_EOF:
            fclose(file);
            return code;
        default:
            fclose(file);
            free(code);
            printf("error in simu8051_load_hexfile.\n");
            return NULL;
        }
    }
    fclose(file);
    return code;
}
void simu8051_dump_regs(void)
{
    printf("\t R0=%2x,R1=%2x,R2=%2x,R3=%2x,\n"
           "\t R4=%2x,R5=%2x,R6=%2x,R7=%2x,\n"
           "\t a=%2x,b=%2x,sp=%2x,dptr=%04x,\n"
           "\t pc=%04x,cycle=%x,psw=%2x,0x20=%2x\n",
           simu8051_read(MEM_TYPE_IRAM, 0),
           simu8051_read(MEM_TYPE_IRAM, 1),
           simu8051_read(MEM_TYPE_IRAM, 2),
           simu8051_read(MEM_TYPE_IRAM, 3),
           simu8051_read(MEM_TYPE_IRAM, 4),
           simu8051_read(MEM_TYPE_IRAM, 5),
           simu8051_read(MEM_TYPE_IRAM, 6),
           simu8051_read(MEM_TYPE_IRAM, 7),
           simu8051_read(MEM_TYPE_SFR, SFR_ACC),
           simu8051_read(MEM_TYPE_SFR, SFR_B),
           simu8051_read(MEM_TYPE_SFR, SFR_SP),
           simu8051_read(MEM_TYPE_SFR, SFR_DPH) << 8 | simu8051_read(MEM_TYPE_SFR, SFR_DPL),
           simu8051_pc(),
           simu8051_cycle(),
           simu8051_read(MEM_TYPE_SFR, SFR_PSW),
           simu8051_read(MEM_TYPE_IRAM, 0x20));
}
